package com.songshijun.controller;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.songshijun.dto.request.ProcessInstanceRequest;
import com.songshijun.dto.response.ProcessInstanceResponse;
import com.songshijun.entity.ApprovalLevel;
import com.songshijun.entity.FlowInfo;
import com.songshijun.entity.Role;
import com.songshijun.entity.User;
import com.songshijun.dto.response.TaskResponse;
import com.songshijun.mapper.ApprovalLevelMapper;
import com.songshijun.service.FlowInfoService;
import com.songshijun.service.UserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.activiti.engine.*;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricProcessInstanceQuery;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.activiti.engine.task.TaskQuery;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import java.text.ParseException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 前端控制器
 * </p>
 *
 * @author 宋时俊
 * @since 2022-01-19
 */
@Slf4j
@RestController
@RequestMapping("/api/flowInfo")
@Api(value = "/api/flowInfo", tags = {"流程部署"})
public class FlowInfoController {

    @Autowired
    private FlowInfoService flowInfoService;
    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private HistoryService historyService;
    @Autowired
    private IdentityService identityService;
    @Autowired
    private ApprovalLevelMapper approvalLevelMapper;
    @Autowired
    private UserService userService;

    @Transactional(rollbackFor = Exception.class)
    @PostMapping("/flow/deployment/{id}")
    @ApiOperation(value = "部署流程，传FlowInfo表id")
    public String deployment(@PathVariable(name = "id") Long id) {

        FlowInfo flowInfo = flowInfoService.getById(id);
        if (flowInfo == null) {
            throw new RuntimeException("未查到流程模型");
        }

//        if (ObjectUtil.equal(1, flowInfo.getState())) {
//            // 如果已部署，更新
//
//        }
        Deployment deployment = repositoryService.createDeployment()
                .addClasspathResource(flowInfo.getFilePath()) // 添加bpmn资源
                .name(flowInfo.getFlowKey())
                .deploy();

        log.info("部署信息 {}", deployment);
        flowInfo.setState(1);
        flowInfoService.updateById(flowInfo);
        return "部署成功";
    }

    @Transactional(rollbackFor = Exception.class)
    @PostMapping("/flow/startProcess")
    @ApiOperation(value = "开始流程，传flowKey, userName")
    public String startProcess(@RequestParam(name = "flowKey") String flowKey, @RequestParam(name = "userName") String userName) {

        User user = userService.getOne(Wrappers.<User>lambdaQuery().eq(User::getUserName, userName).last("LIMIT 1"));
        if (null == user) {
            throw new RuntimeException("未查到用户");
        }

        Map<String, Object> variables = new HashMap<>();
        // 设置发起人
        variables.put("starter", user.getActUserId());

        // 查询审批级别
        List<ApprovalLevel> flowKeyLevel = approvalLevelMapper.getFlowKeyLevel(flowKey);
        if (CollUtil.isNotEmpty(flowKeyLevel)) {
            for (ApprovalLevel approvalLevel : flowKeyLevel) {
                // 查询该审批级别参与的角色
                List<Role> roleFlowKeyLevel = approvalLevelMapper.getRoleFlowKeyLevel(flowKey, approvalLevel.getApproveLevel());
                if (CollUtil.isNotEmpty(flowKeyLevel)) {
                    Set<String> collect = roleFlowKeyLevel.stream().map(Role::getRoleKey).collect(Collectors.toSet());
                    variables.put(approvalLevel.getApproveKey(), StrUtil.join(",", collect));
                }
            }
        }

        //设置发起人
        identityService.setAuthenticatedUserId(user.getActUserId());

        // 启动流程
        log.info("启动流程: 发起人 = {}, 流程key flowKey = {}, 变量variables = {}",user.getActUserId(), flowKey, variables);
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(flowKey, variables);
        Task task = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();

        Map<String, Object> args = new HashMap<>();
        args.put("type", "Y");
        taskService.complete(task.getId(), args);
        return "申请成功";
    }


    @GetMapping("/myTask")
    @ApiOperation(value = "获取我的任务，传userName")
    public List<TaskResponse> getMyTask(@RequestParam(name = "userName") String userName, @RequestParam(name = "pageNum", defaultValue = "1") Integer pageNum, @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize) {

        User user = userService.getOne(Wrappers.<User>lambdaQuery().eq(User::getUserName, userName).last("LIMIT 1"));
        if (null == user) {
            throw new RuntimeException("未查到用户");
        }
        TaskQuery query = taskService.createTaskQuery().taskCandidateOrAssigned(user.getActUserId())
                .orderByTaskCreateTime().desc();
        List<Task> myTaskList = query.listPage((pageNum - 1) * pageSize, pageSize);

        List<TaskResponse> taskResponseList = new ArrayList<>();
        for (Task task : myTaskList) {
            TaskResponse response = new TaskResponse();
            String processInstanceId = task.getProcessInstanceId();
            HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
                    .processInstanceId(processInstanceId).singleResult();
            response.setTaskId(task.getId());
            response.setProcessName(historicProcessInstance.getProcessDefinitionName());
            response.setCreateTime(historicProcessInstance.getStartTime());
            response.setCreater(historicProcessInstance.getStartUserId());
            response.setInstanceId(processInstanceId);
            taskResponseList.add(response);
        }
        return taskResponseList;
    }

    @Transactional(rollbackFor = Exception.class)
    @PostMapping("/complete")
    @ApiOperation(value = "完成任务，传userName, taskId, approve(同意-Y，拒绝-N)")
    public String completeTask(@RequestParam(name = "userName") String userName, @RequestParam(name = "taskId") String taskId, @RequestParam(name = "approve", defaultValue = "Y") String approve) {
        User user = userService.getOne(Wrappers.<User>lambdaQuery().eq(User::getUserName, userName).last("LIMIT 1"));
        if (null == user) {
            throw new RuntimeException("未查到用户");
        }

        Task task = this.taskService.createTaskQuery().taskId(taskId).singleResult();
        Map<String, Object> map = new HashMap<>();
        map.put("assignee", user.getActUserId());
        map.put("type", approve);
        taskService.setVariablesLocal(task.getId(), map);
        taskService.complete(taskId, map);
        return "操作成功";
    }

    @GetMapping("/getMyInstance")
    @ApiOperation(value = "查询我发起的某个流程定义的实例列表")
    public IPage<ProcessInstanceResponse> getMyInstance(ProcessInstanceRequest request) throws ParseException {
        String name = request.getName();
        String beginTime = request.getBeginTime();
        String endTime = request.getEndTime();
        String processKey = request.getProcessKey();
        String status = request.getStatus();

        Integer pageNum = request.getPageNum();
        Integer pageSize = request.getPageSize();

        User user = userService.getOne(Wrappers.<User>lambdaQuery().eq(User::getUserName, request.getUserName()).last("LIMIT 1"));
        if (null == user) {
            throw new RuntimeException("未查到用户");
        }

        HistoricProcessInstanceQuery query = historyService.createHistoricProcessInstanceQuery()
                .startedBy(user.getActUserId())
                .orderByProcessInstanceStartTime()
                .desc();
        if(StringUtils.isNotBlank(name)){
            query.processInstanceNameLike(name);
        }
        if(StringUtils.isNotBlank(beginTime)){
            Date beginTime_date = DateUtils.parseDate(beginTime, "yyyy-MM-dd");
            query.startedAfter(beginTime_date);
        }
        if(StringUtils.isNotBlank(endTime)){
            Date endTime_date = DateUtils.parseDate(endTime, "yyyy-MM-dd");
            query.startedBefore(endTime_date);
        }
        if(StringUtils.isNotBlank(processKey)){
            query.processDefinitionKey(processKey);
        }
        if(StringUtils.isNotBlank(status)){
            if(StringUtils.equals("act_complete_type_001", status)){
                //已完成
                query.finished();
            }else{
                //未完成
                query.unfinished();
            }
        }
        List<HistoricProcessInstance> listPage = query.listPage((pageNum - 1) * pageSize, pageSize);

        IPage<ProcessInstanceResponse> iPage = new Page<>(request.getPageNum(), request.getPageSize(), listPage.size());
        List<ProcessInstanceResponse> responseList = new ArrayList<>();

        for (HistoricProcessInstance processInstance : listPage) {
            ProcessInstanceResponse response = new ProcessInstanceResponse();
            response.setId(processInstance.getId());
            response.setBusinessKey(processInstance.getBusinessKey());
            response.setProcessDefinitionId(processInstance.getProcessDefinitionId());
            response.setProcessDefinitionKey(processInstance.getProcessDefinitionKey());
            response.setProcessDefinitionName(processInstance.getProcessDefinitionName());
            response.setEndTime(processInstance.getEndTime());
            response.setStartTime(processInstance.getStartTime());
            response.setStartUserId(processInstance.getStartUserId());
            if(processInstance.getEndTime() != null){
                response.setCompleteType("act_complete_type_001");
            }else{
                response.setCompleteType("act_complete_type_002");
            }
            responseList.add(response);

        }
        iPage.setRecords(responseList);

        return iPage;
    }

}
